﻿using System.Collections.Generic;
using System.Linq;
using net.entity.framework.cache;
using net.entity.framework.query;

namespace net.entity.framework.db {
    public class DbRepository {
        private static readonly DbRepository instance = new DbRepository();

        public static DbRepository Instance {
            get { return instance; }
        }

        #region Methods

        /// <summary>
        /// Finds all the items. Eager evaluation
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> FindAll<T>() where T : EntityRef {
            return Find<T>(true).ToList();
        }

        /// <summary>
        /// Retrieves subset of records from the database matching the expression
        /// </summary>
        public IEnumerable<T> Find<T>(QueryClause whereClause, params Terminal[] orderBy) where T : EntityRef {
            var root = EntityRef.GetQueryRoot<T>();
            var result = Eql.Select(root).Where(whereClause).OrderBy(orderBy).Execute<T>().ToList();
            EntityCache.Instance.AddEntityRefs(result); //put the items into EntityCache
            return result;
        }

        /// <summary>
        /// Retrieves EqlEntityRef given an expression
        /// </summary>
        public T FindFirst<T>(QueryClause whereClause, bool strict) where T : EntityRef {
            var root = EntityRef.GetQueryRoot<T>();
            var result = Eql.Select(root).Where(whereClause).ExecuteScalar<T>(strict);
            EntityCache.Instance.AddEntityRef(result); //put the item into EntityCache
            return result;
        }

        /// <summary>
        /// Retrieves EqlEntityRef given an Id and revision.
        /// </summary>
        public T FindFirst<T>(int id, int revision, bool strict) where T : EntityRef {
            var root = EntityRef.GetQueryRoot<T>();
            var whereClause = root.Id == id;
            if (revision > -1) {
                whereClause &= root.Revision == revision;
            }
            return FindFirst<T>(whereClause, strict);
        }


        public void Commit<T>(IEnumerable<T> entities) where T : Entity {
            GraphCommiter.GetInstance.Commit(entities);
        }


        /// <summary>
        /// Deletes multiples items in batch operation.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        public void Delete<T>(IEnumerable<T> items) where T : Entity {
            foreach (var entity in items) {
                entity.IsDeleted = true;
            }
            Commit(items);
        }

        /// <summary>
        /// Deletes items by condition.
        /// </summary>
        public int Delete<T>(QueryClause whereClause) where T : EntityRef {
            var deleteRoot = EntityRef.GetQueryRoot<T>();
            return Eql.Delete(deleteRoot).Where(whereClause).Execute();
        }

        #endregion
    }
}